import {
  PivotConfig,
  Query,
  ResultSet,
  Series,
  TimeDimensionGranularity,
} from '@cubejs-client/core'
import { ChartType, formatDate } from '@/components/charts/base.ts'
import dayjs from 'dayjs'
import utils from 'xe-utils'
import * as echarts from 'echarts'

export function useCharts(props: {
  results: ResultSet
  query: Query
  chartType: ChartType
  extend: null | '同比' | '环比'
}) {
  const { results, query, chartType, extend } = props

  const getGranularityTime = () => {
    const { timeDimensions } = query

    return (timeDimensions || []).filter((time) => !!time.granularity)
  }

  const getPivotConfig = (): PivotConfig => {
    const { dimensions, timeDimensions, measures } = query
    const times = getGranularityTime()
    const limit = query.limit || 1000
    if (times.length > 0) {
      return {
        x: [...times.map((t) => t.dimension)],
        y: ['measures', ...(dimensions || [])],
        fillMissingDates: limit > 1,
      }
    } else {
      return {
        x: ['dimensions'],
        y: ['measures'],
        fillMissingDates: limit > 1,
      }
    }
  }

  function getActualWidthOfChars(text: string, options = {}) {
    const { size = 14, family = 'Honeywell Sans Web, Verdana, sans-serif' } = options

    let canvas = document.createElement('canvas')

    const ctx = canvas.getContext('2d')

    ctx!.font = `${size}px ${family}`

    const metrics = ctx!.measureText(text)

    const actual =
      Math.abs(metrics.actualBoundingBoxLeft) + Math.abs(metrics.actualBoundingBoxRight)

    canvas = null

    return Math.max(metrics.width, actual)
  }

  const getGranularity = () => {
    let granularity = undefined

    if (query.timeDimensions) {
      query.timeDimensions.forEach((time) => {
        granularity = time.granularity
      })
    }
    return granularity
  }

  const isCompareDateRangeQuery = () => {
    return !!results.loadResponse.results.find(
      (result: any) => result.query.queryType == 'compareDateRangeQuery',
    )
  }

  const getCompareDate = () => {
    if (isCompareDateRangeQuery()) {
      if (query.timeDimensions && query.timeDimensions.length > 0) {
        const ranges = query.timeDimensions[0].compareDateRange
        return ranges.slice(1, ranges.length).map((range: string[]) => {
          return `${range[0]}T00:00:00.000 - ${range[1]}T23:59:59.999`
        })
      } else {
        return []
      }
    } else {
      return []
    }
  }

  const getChartData = () => {
    const pivotConfig = getPivotConfig()
    const chartPivot = results.chartPivot(pivotConfig)
    const seriesName = results.seriesNames(pivotConfig)
    const series = results.series(pivotConfig)
    seriesName.forEach((col) => {
      if (isCompareDateRangeQuery()) {
        const compareDate = getCompareDate()
        const shorts = col.shortTitle.split(', ')
        if (shorts.length > 1 && compareDate.includes(shorts[0])) {
          col.shortTitle = shorts[shorts.length - 1] + `（${extend}）`
        } else {
          col.shortTitle = shorts[shorts.length - 1]
        }
      }
    })

    series.forEach((row) => {
      row.series.forEach((s) => {
        s.key = row.key
      })
    })

    return {
      chartPivot,
      seriesName,
      series,
    }
  }

  const getTooltip = () => {
    return {
      trigger: 'axis',
      axisPointer: {
        type: 'cross',
        crossStyle: {
          color: '#999',
        },
      },
    }
  }

  const getColor = () => {
    return [
      '#1664FF',
      '#FFC400',
      '#1AC6FF',
      '#FF8A00',
      '#3CC780',
      '#7442D4',
      '#304D77',
      '#B48DEB',
      '#009488',
      '#FF7DDA',
    ]
  }

  const getXAxisValue = (value: string, granularity?: TimeDimensionGranularity) => {
    if (granularity) {
      if (dayjs(value, 'YYYY-MM-DDTHH:mm:ss.SSS', true).isValid()) {
        return formatDate(value, granularity!)
      }
      return value
    } else {
      return value
    }
  }

  const getPieLeft = (len: number, index: number) => {
    const block = 100 / len

    return block * index + block / 2 + '%'
  }

  const getDimensions = () => {
    const dimensions = [...(query.dimensions || [])]

    if (query.timeDimensions) {
      query.timeDimensions.forEach((dimension) => {
        if (!dimensions.includes(dimension.dimension)) {
          dimensions.push(dimension.dimension)
        }
      })
    }
    return dimensions
  }

  /**
   * 同比和环比的曲线
   */
  const getExtendSeries = (series: Series<any>[]) => {
    if (!extend) return []
    const config: any[] = []
    if (series.length > 1) {
      const target = series[0]
      series.forEach((row: any, index) => {
        if (index > 0) {
          config.push({
            key: '__rate',
            name: '增长率',
            type: 'line',
            label: {
              show: true,
              position: 'top',
              formatter: ({ value }: any) => {
                return value + '%'
              },
            },

            tooltip: {
              valueFormatter: (value: any) => {
                return value + ' %'
              },
            },
            data: target.series.map((item, i: number) => {
              const tValue = row.series[i].value
              return {
                value:
                  item.value && tValue ? (((item.value - tValue) * 100) / tValue).toFixed(2) : '-',
                x: item.x,
              }
            }),
          })
        }
      })
    }

    return config
  }

  const getMeasureUnit = (key: string) => {
    const { queryItems } = props.results.loadResponse
    const ll = key.split(',')
    const measure = ll[ll.length - 1]
    const target = queryItems.find((item: any) => item.type === 'measure' && item.name == measure)
    return target ? target.unit || '' : ''
  }

  const getMeasureAccuracy = (key: string, value: any) => {
    const { queryItems } = props.results.loadResponse
    const ll = key.split(',')
    const measure = ll[ll.length - 1]
    const target = queryItems.find((item: any) => item.type === 'measure' && item.name == measure)
    const accuracy = target ? target.accuracy : null
    if (accuracy != null) {
      return utils.commafy(value, { digits: accuracy })
    } else {
      return utils.commafy(value)
    }
  }

  const getAxis = (series: any[], type = 'yAxisIndex') => {
    const { queryItems } = props.results.loadResponse
    const units: any = {
      defaults: [],
    }
    const maps = utils.uniq(
      series.map((s) => {
        const ss = s.key.split(',')
        return ss[ss.length - 1]
      }),
    )

    maps.forEach((name: string) => {
      const item = queryItems.find((q) => q.name == name)
      if (item && item.unit) {
        if (units[item.unit]) {
          units[item.unit].push(name)
        } else {
          units[item.unit] = [name]
        }
      } else {
        units.defaults.push(name)
      }
    })

    const uniq: string[] = []

    for (let key in units) {
      if (key == 'defaults') {
        uniq.push(...units[key])
      } else {
        uniq.push(units[key][0])
      }
    }
    const list = uniq.map((key, index) => {
      const keys: string[] = []
      for (const unit in units) {
        if (units[unit].includes(key)) {
          keys.push(...units[unit])
        }
      }
      const targets = series.filter((s) => {
        const ll = s.key.split(',')
        return keys.includes(ll[ll.length - 1])
      })
      const item = queryItems.find((q: any) => q.name == key)

      targets.forEach((target) => {
        target[type] = index
      })
      if (key == '__rate') {
        return {
          type: 'value',
          offset: 0,
          key: key,
          name: '',
          nameTextStyle: {
            fontSize: 10,
          },
          splitLine: {
            show: true,
            lineStyle: {
              type: 'dashed',
            },
          },
          axisLabel: {
            formatter: '{value} %',
          },
        }
      } else {
        // const item = queryItems.find((item: any) => item.name == key)
        return {
          offset: 0,
          type: 'value',
          splitLine: {
            show: true,
            lineStyle: {
              type: 'dashed',
            },
          },
          nameTextStyle: {
            fontSize: 10,
          },
          key: key,
          name: item?.unit || '',
        }
      }
    })

    if (list.length > 2) {
      list.forEach((axis, index) => {
        if (index >= 2) {
          const key = uniq[index]
          const serie = series.find((s) => {
            const ll = s.key.split(',')
            return ll[ll.length - 1] == key
          })
          const max = Math.max(...serie.data.map((s: any) => s.value))
          const width = getActualWidthOfChars(parseInt(max).toString())
          axis.offset = list[index - 1].offset + width + 30
        }
      })

      return list
    } else {
      return list
    }
  }

  function getSeries(chartType: ChartType, series: any[], seriesName: any[]) {
    return series.map((row, index) => {
      return {
        key: row.key,
        name: seriesName[index].shortTitle,
        type: chartType,
        data: row.series.map((row: any) => {
          row.itemStyle = {
            borderRadius: row.value >= 0 ? [4, 4, 0, 0] : [0, 0, 4, 4], // 设置圆角
          }
          if (row.value === 0) {
            row.itemStyle['color'] = 'rgba(0,0,0,0)'
          }
          return row
        }),
        barMaxWidth: 50,
        barMinHeight: 8,
        label: {
          show: true,
          position: 'top',
          formatter: ({ value }: any) => {
            return value == 0 ? '' : getMeasureAccuracy(row.key, value)
          },
        },
        tooltip: {
          valueFormatter: (value: any) => {
            return getMeasureAccuracy(row.key, value) + ' ' + getMeasureUnit(row.key)
          },
        },
      }
    })
  }

  function getLegendCount(name: string, series: any) {
    const { queryItems } = props.results.loadResponse
    const target = series.find((s: any) => s.name == name)
    const ll = target.key.split(',')
    const measure = ll[ll.length - 1]
    const item = queryItems.find((item: any) => item.name == measure)
    if (item.format == 'percent') {
      return ''
    } else {
      const total = target.data.reduce((t, s) => {
        return t + s.value
      }, 0)

      return `
      <div class="mt-5">
      累计：<span class="font-bold">${utils.commafy(total, { digits: item ? item.accuracy : null })} ${item.unit || ''}</span>
</div>
      `
    }
  }

  function getAxisLabel() {
    return {
      rotate: 45,
      margin: 10,
      textStyle: {
        fontSize: '11px',
      },
      formatter: (value: any) => {
        value = value.slice(0, 24)
        let str = ''
        let num = 12 //每行显示字数
        let valLength = value.length //该项x轴字数
        let rowNum = Math.ceil(valLength / num) // 行数

        if (rowNum > 1) {
          for (let i = 0; i < rowNum; i++) {
            let temp = ''
            let start = i * num
            let end = start + num
            temp = value.substring(start, end) + '\n'
            str += temp
          }
          return str
        } else {
          return value
        }
      },
    }
  }

  const getOption = () => {
    const { series, chartPivot, seriesName } = getChartData()

    if (series.length == 0) {
      return null
    }

    const granularity = getGranularity()
    const response = props.results.loadResponse as any
    switch (chartType) {
      case 'bar':
      case 'line':
        const extendSeries = getExtendSeries(series)
        const list = getSeries(chartType, series, seriesName)
        const allSeries = [...list, ...extendSeries]
        const yAxis = getAxis(allSeries)
        return {
          color: getColor(),
          grid: {
            containLabel: true,
            left: 20,
            bottom: 25,
            right: 50,
            top: 30,
          },
          legend: {
            type: 'scroll',
            bottom: 5,
            tooltip: {
              show: true,
              formatter: (params: any) => {
                const count = getLegendCount(params.name, allSeries)
                return `
                <div>${params.name}</div>
                ${count}
              `
              },
            },
          },
          tooltip: getTooltip(),
          xAxis: {
            data: series[0].series.map((row) => getXAxisValue(row.x, granularity)),
            axisLabel: getAxisLabel(),
          },
          yAxis: yAxis,
          series: allSeries,
        }

      case 'stack': {
        const allSeries = getSeries('bar', series, seriesName)

        allSeries.forEach((series: any) => {
          series.stack = 'total'
          delete series.label.position
        })
        const yAxis = getAxis(allSeries)
        return {
          color: getColor(),
          grid: {
            containLabel: true,
            left: 20,
            bottom: 25,
            right: 50,
            top: 30,
          },
          legend: {
            type: 'scroll',
            bottom: 5,
            tooltip: {
              show: true,
              formatter: (params: any) => {
                const count = getLegendCount(params.name, allSeries)
                return `
                <div>${params.name}</div>
                ${count}
              `
              },
            },
          },
          tooltip: {
            trigger: 'axis',
            axisPointer: {
              type: 'cross',
              crossStyle: {
                color: '#999',
              },
            },
            formatter: (params) => {
              const serie = params[0]
              let t = 0
              params.forEach((param) => {
                t += param.value
              })
              return `
              <div class="text-15 mb-10">${serie.name} </div>
              ${params
                .reverse()
                .map((param) => {
                  return `
                  <div class="flex justify-between">
                   <span class="flex-1 mr-20">${param.marker} ${param.seriesName}</span> <strong>${getMeasureAccuracy(param.data.key, param.value)} ${getMeasureUnit(param.data.key)}</strong>
                </div>
                  `
                })
                .join('')}
              
              <div class="flex mt-8 pt-5"  border-t="1px solid light_border">
              <span >&nbsp;&nbsp;&nbsp;&nbsp;</span>
              <span class="flex-1">合计</span>
              <strong>
              ${getMeasureAccuracy(serie.data.key, t)} ${getMeasureUnit(serie.data.key)}
</strong>
</div>
              `
            },
          },
          xAxis: {
            data: series[0].series.map((row) => getXAxisValue(row.x, granularity)),
            axisLabel: getAxisLabel(),
          },
          yAxis: yAxis,
          series: allSeries,
        }
      }

      case 'horizontalBar': {
        const extendSeries = getExtendSeries(series)
        const list = series.map((row, index) => {
          return {
            key: row.key,
            name: seriesName[index].shortTitle,
            type: 'bar',
            data: row.series.reverse(),
            barMaxWidth: 50,
            label: {
              show: true,
              position: 'right',
              formatter: ({ value }: any) => {
                return value == 0 ? '' : getMeasureAccuracy(row.key, value)
              },
            },
            itemStyle: {
              borderRadius: [0, 4, 4, 0], // 设置圆角
            },
            tooltip: {
              valueFormatter: (value: any) => {
                return getMeasureAccuracy(row.key, value) + ' ' + getMeasureUnit(row.key)
              },
            },
          }
        })

        const allSeries = [...list, ...extendSeries]
        return {
          color: getColor(),
          grid: {
            containLabel: true,
            bottom: 60,
            top: '12%',
            left: 20,
            right: 40,
          },
          legend: {
            type: 'scroll',
            bottom: 5,
            tooltip: {
              show: true,
              formatter: (params: any) => {
                const count = getLegendCount(params.name, allSeries)
                return `
                <div>${params.name}</div>
                ${count}
              `
              },
            },
          },
          tooltip: getTooltip(),
          yAxis: {
            type: 'category',
            data: series[0].series.map((row) => getXAxisValue(row.x, granularity)),
          },
          xAxis: getAxis(allSeries, 'xAxisIndex'),
          series: allSeries,
        }
      }

      case 'pie': {
        return {
          tooltip: { trigger: 'item' },
          title: series.map((row: any, index) => {
            return {
              text: seriesName[index].shortTitle,
              left: getPieLeft(series.length, index),
              top: '38%',
              textAlign: 'center',
              padding: 0,
              textStyle: {
                fontSize: 12,
              },
            }
          }),
          legend: {
            type: 'scroll',
            bottom: 10,
          },
          series: series.map((row: any, index) => {
            return {
              color: getColor(),
              name: seriesName[index].shortTitle,
              radius: [40, 80],
              type: chartType,
              tooltip: {
                valueFormatter: (value: any) => {
                  return value + ' ' + getMeasureUnit(series[index].key)
                },
              },
              center: [getPieLeft(series.length, index), '40%'],
              data: row.series.map((data: any, i: number) => {
                let name = getXAxisValue(data.x, granularity)
                return {
                  value: Math.abs(data.value),
                  name: !name ? seriesName[index].shortTitle : name,
                  key: data.key,
                  x: !name ? seriesName[index].shortTitle : name,
                }
              }),
            }
          }),
        }
      }

      case 'wordCloud': {
        return {
          tooltip: { trigger: 'item' },

          legend: {
            type: 'scroll',
            bottom: 10,
            show: false,
          },
          series: response.results.map((row: any, index) => {
            return {
              color: getColor(),
              name: seriesName[index].shortTitle,
              radius: [40, 80],
              shape: 'circle',
              bottom: 50,
              shrinkToFit: true,
              textStyle: {
                fontFamily: 'sans-serif',
                fontWeight: 'bold',
                // Color can be a callback function or a color string
                color: function () {
                  // Random color
                  return (
                    'rgb(' +
                    [
                      Math.round(Math.random() * 160),
                      Math.round(Math.random() * 160),
                      Math.round(Math.random() * 160),
                    ].join(',') +
                    ')'
                  )
                },
              },
              type: chartType,
              tooltip: {
                valueFormatter: (value: any) => {
                  return value + ' ' + getMeasureUnit(series[index].key)
                },
              },
              center: [getPieLeft(response.results.length, index), '40%'],
              data: row.data.map((data: any, i: number) => {
                let name: string[] = []

                getDimensions().forEach((dimension) => {
                  name.push(getXAxisValue(data[dimension], granularity))
                })

                const key = series[index].key.split(',')
                const measure = key[key.length - 1]
                return {
                  value: data[measure],
                  name: name.join(' '),
                }
              }),
            }
          }),
        }
      }
    }
  }

  return {
    getOption,
  }
}
